package ar.com.spsolutions.splilabrary.view.components;

import java.util.Collection;
import java.util.List;

import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.authorization.Action;
import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
import org.apache.wicket.extensions.markup.html.form.palette.Palette;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.ChoiceRenderer;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.EmailTextField;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.IChoiceRenderer;
import org.apache.wicket.markup.html.form.PasswordTextField;
import org.apache.wicket.markup.html.form.TextArea;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.model.ResourceModel;

import ar.com.spsolutions.splibrary.entity.Entity;
import ar.com.spsolutions.splibrary.general.RoleConverterService.RolesEnum;
import ar.com.spsolutions.splibrary.services.dto.AbstractCRUDDTO;
import ar.com.spsolutions.splilabrary.view.utils.StringUtils;

public class CRUDComponent<E extends Entity> extends WebMarkupContainer {

	private static final long serialVersionUID = 8820125885620972162L;

	private AbstractCRUDDTO<E> genericCRUDDTO;
	private Form<AbstractCRUDDTO<E>> mainForm;
	private Header<E> header;

	public CRUDComponent(final String id, final String headerId,
			final String footerId, final String dataFormId,
			final AbstractCRUDDTO<E> genericCRUDDTO,
			final String[] headerColumns) {
		super(id);
		this.setGenericCRUDDTO(genericCRUDDTO);
		this.mainForm = this.createForm(dataFormId, genericCRUDDTO);
		this.add(this.mainForm);
		new Footer<E>(footerId, genericCRUDDTO, this);
		this.header = new Header<E>(headerId, genericCRUDDTO, this,
				headerColumns);
		this.add(this.header);
		this.initVisibility();
	}

	private void initVisibility() {
		this.getMainForm().setVisible(false);
	}

	private Form<AbstractCRUDDTO<E>> createForm(final String dataFormId,
			final AbstractCRUDDTO<E> dto) {
		final Form<AbstractCRUDDTO<E>> form = new Form<AbstractCRUDDTO<E>>(
				dataFormId, new CompoundPropertyModel<AbstractCRUDDTO<E>>(dto));
		form.setOutputMarkupId(true);
		form.setOutputMarkupPlaceholderTag(true);
		return form;
	}

	public AbstractCRUDDTO<E> getAbstractCRUDDTO() {
		return this.getGenericCRUDDTO();
	}

	public void setAbstractCRUDDTO(final AbstractCRUDDTO<E> aGenericCRUDDTO) {
		this.setGenericCRUDDTO(aGenericCRUDDTO);
	}

	public void addText(final String id, final String labelId) {
		this.addComponent(labelId, new TextField<Object>(id));
	}

	public void addText(final String id, final String labelId,
			final RolesEnum role) {
		this.addComponent(labelId, new TextField<Object>(id), role);
	}

	public void addTextArea(final String id, final String labelId) {
		this.addComponent(labelId, new TextArea<Object>(id));
	}

	public void addTextArea(final String id, final String labelId,
			final RolesEnum role) {
		this.addComponent(labelId, new TextArea<Object>(id), role);
	}

	public void addEmail(final String id, final String labelId,
			final RolesEnum role) {
		this.addComponent(labelId, new EmailTextField(id), role);
	}

	public void addEmail(final String id, final String labelId) {
		this.addComponent(labelId, new EmailTextField(id));
	}

	public void addPassword(final String id, final String labelId) {
		this.addPassword(id, labelId, null);
	}

	public void addPassword(final String id, final String labelId,
			final RolesEnum role) {
		final PasswordTextField textField = new PasswordTextField(id);
		textField.setResetPassword(false);
		this.addComponent(labelId, textField, role);
	}

	private void addComponent(final String labelId, final Component component) {
		this.addComponent(labelId, component, null);
	}

	private void addComponent(final String labelId, final Component component,
			final RolesEnum role) {
		final Form<AbstractCRUDDTO<E>> form = this.getMainForm();
		final Label label = new Label(labelId, new ResourceModel(labelId,
				labelId));
		this.addLabel(label, form);
		this.addFormComponent(component, form);
		if (role != null) {
			MetaDataRoleAuthorizationStrategy.authorize(label, new Action(
					Action.RENDER), role.toString());
			MetaDataRoleAuthorizationStrategy.authorize(component, new Action(
					Action.RENDER), role.toString());
		}
	}

	private void addFormComponent(final Component component,
			final Form<AbstractCRUDDTO<E>> form) {
		component.setOutputMarkupId(true);
		component.setOutputMarkupPlaceholderTag(true);
		form.add(component);
	}

	private void addLabel(final Label label, final Form<AbstractCRUDDTO<E>> form) {
		label.setOutputMarkupId(true);
		label.setOutputMarkupPlaceholderTag(true);
		form.add(label);
	}

	public void addComboChoice(final String id, final String labelId,
			final RolesEnum role) {
		final ChoiceRenderer<Object> renderer = new ChoiceRenderer<Object>(this
				.getGenericCRUDDTO().getRenderPropertyFor(id));
		final PropertyModel<List<Object>> choices = new PropertyModel<List<Object>>(
				this.getGenericCRUDDTO(), id + "s");
		this.addComponent(labelId, new DropDownChoice<Object>(id,
				new PropertyModel<Object>(this.getGenericCRUDDTO(), id),
				choices, renderer), role);
	}

	public void addComboChoice(final String id, final String labelId) {
		this.addComboChoice(id, labelId, null);
	}

	public void addPalette(final String id, final String labelId) {
		this.addPalette(id, labelId, null);
	}

	public void addPalette(final String id, final String labelId,
			final RolesEnum role) {
		final IModel<? extends List<? extends Object>> model = new PropertyModel<List<? extends Object>>(
				this.getGenericCRUDDTO(), id);
		final String all = StringUtils.upperSelecteds(
				StringUtils.getMethodName("all/0/", id), 4);
		final IModel<? extends Collection<? extends Object>> choicesModel = new PropertyModel<Collection<? extends Object>>(
				this.getGenericCRUDDTO(), all);
		final IChoiceRenderer<Object> choiceRenderer = new ChoiceRenderer<Object>(
				this.getGenericCRUDDTO().getRenderPropertyFor(id));
		final Palette<Object> palette = new Palette<Object>(id, model,
				choicesModel, choiceRenderer, 10, false);
		this.addComponent(labelId, palette, role);
	}

	public void showFormFor(final AbstractCRUDDTO<E> formModel,
			final AjaxRequestTarget target) {
		final Form<AbstractCRUDDTO<E>> mForm = this.getMainForm();
		mForm.setVisible(true);
		mForm.setModelObject(formModel);
		mForm.modelChanged();
		target.add(mForm);
	}

	public void hideForm(final AjaxRequestTarget target) {
		this.getMainForm().setVisible(false);
		target.add(this.getMainForm());
		this.getHeader().hideResultTable(target);
	}

	public Form<AbstractCRUDDTO<E>> getMainForm() {
		return this.mainForm;
	}

	public void setMainForm(final Form<AbstractCRUDDTO<E>> mainForm) {
		this.mainForm = mainForm;
	}

	public Header<E> getHeader() {
		return this.header;
	}

	public void setHeader(final Header<E> header) {
		this.header = header;
	}

	public AbstractCRUDDTO<E> getGenericCRUDDTO() {
		return this.genericCRUDDTO;
	}

	public void setGenericCRUDDTO(final AbstractCRUDDTO<E> genericCRUDDTO) {
		this.genericCRUDDTO = genericCRUDDTO;
	}

}
